home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-09-16 | 52.5 KB | 1,292 lines | [TEXT/CCL2] |
- ;;
- ;; (try to) Crunch an MPW pascal equates file into the (more or less)
- ;; equivalent lisp file.
- ;;
- ;; Joe Chung, Apple Computers
- ;; June 1990
- ;;
- ;; Change log.
- ;;
- ;; 06/02/93 bill format-deftrap outputs in lower case again (it shouldn't have done
- ;; so when Joe ran it the first time, but print wasn't obeying
- ;; readtable-case yet, then.
- ;; JBK's changes to parse-type so that it will handle the OCE interfaces.
- ;; ------------- 2.1d6
- ;; 03/10/93 bill (ignore char) in pasc-read-asterisk
- ;; 05/29/92 bill :dont-output-includes keyword to translate-pasc-file.
- ;; Handle ** as an operator.
- ;; ------------ 2.0
- ;; 12/19/91 bill don't rely on (fboundp 'ccl::xxx-trap-macro-function) being true.
- ;; 12/17/91 bill alanr's addition to the 2f3c inline in generate-deftrap
- ;; parse-inline makes special dispensation for $x+$y.
- ;; Both of these changes are to make the QuickTime interfaces translate.
- ;; ------------ 2.0b4
- ;; 4/19/91 joe store all *handle-tos* keys as keywords
- ;; 04/08/91 joe make sure unknown types are at least keyworded. fix unknown type
- ; error message bug (wasn't working before)
- ;; 02/22/91 bill add str32.
- ;----------- 2.0b1
- ;; 01/07/91 bill Output DEFRECORD for ARRAY types.
- ;; 11/16/90 joe moved top level functions to translate.lisp, fixed a bug in
- ;; (foo, bar, bang) pasc types... now becomes unsigned-byte instead of int.
- ;; *handle-table* -> *pointer-table*
- ;; 10/25/90 bill in translate-type-decl: output :handle with defrecord when appropriate.
- ;; 09/10/90 bill in format-deftrap: prefix trap-name with "_", strip comments (they
- ;; should really be output somewhere.
- ;;
- ;; To do:
- ;; If a pascal record has a field named VARIANT, output "VARIANT" versus VARIANT
- ;; in the Lisp DEFRECORD form.
-
- #|
- Note of apology:
-
- Pascal sucks. I'm not actually apologizing for that. I'm saying that
- I'm sorry that I didn't realize how completely awful it was until I'd already written
- a substantial amount of code. Hence the kludgey nature of this program. A few words
- of explanation might be in order for any who tries to fathom this stuff...
-
- On tokens and symbols: I've hacked the reader a bit so that you can get four different
- kinds of tokens: symbols, numbers, characters, and lists. Symbols include all the normal
- symbols, as well as any hex or binary numbers (i.e. #x23). Numbers are just plain ol'
- numbers, and characters are simply characters. List tokens are only used for comments
- and look like: (:comment ";Comment string"). All the symbol tokens are interned in the
- :translate package, and when they refer to constants, or when they are hex or binary
- numbers, the symbols are bound to their value if possible. Thus, certain pascal compile
- time expressions can be evaluated (yes - buried in this code is an infix expression
- interpreter!). Constants are always "dollarified" by prepending a "$" character in
- front of the constant name. When the constant is referred to, either as part of an
- expression for defining another constant, or in an INLINE function declaration, the
- name is also prepended with "#" character so that the constant will be auto-loaded
- if necessary.
-
- On spellings: Since it is desirable to keep the correct cases of the characters in
- symbol and type names, I keep a hash table called *spellings* to associate the
- two things. Thus the symbol KAEOPENAPPLICATION has the spelling "kAEOpenApplication"ยจ.
-
- On types: The translator maintains a table of type names and types. The types themselves
- are always lists and look like: (<mactype or record> <extra-info>). Records look like
- (<record-name> :record). The other funny things are what I call sets and ranges which
- correspond to pascal type expressions: (foo, bar, bang) and [2..42] respectively. Sets
- always have :unsigned-byte as their mactype, and ranges have :unsigned-byte or :unsigned-
- integer depending on the size of the range. Sets look like:
- (:unsigned-byte :set (item1 item2 ... )), and ranges look like:
- (:unsigned-byte :range (2 42)). We also keep track of records who have types which are
- handles to they record in a table called *handle-tos*. These records are generated so
- that their default storage is :handle.
-
- |#
-
-
- (in-package :translate)
-
- ; set up the readtable for pasc files...
- ;
- (defparameter *comment-column* 32)
-
- (defvar *normal-readtable* *readtable*)
- (defvar *pasc-indent* 0)
- (defvar *pasc-readtable* (copy-readtable nil))
- (defvar *pasc-read-buffer* (make-array 4096 :element-type 'base-character
- :fill-pointer 0))
- (defun pasc-read-comment (stream char)
- (declare (ignore char))
- (setf (fill-pointer *pasc-read-buffer*) 0)
- (vector-push #\; *pasc-read-buffer*)
- (vector-push #\space *pasc-read-buffer*)
- (do ((ch (read-char stream) (read-char stream)))
- ((char= ch #\}) (list :comment (copy-seq *pasc-read-buffer*)))
- (vector-push ch *pasc-read-buffer*)
- (when (char= ch #\newline)
- (vector-push #\; *pasc-read-buffer*)
- (vector-push #\space *pasc-read-buffer*))))
-
- (defun pasc-read-paren (stream char)
- (let ((next (read-char stream)))
- (cond
- ((char= next #\*)
- (setf (fill-pointer *pasc-read-buffer*) 0)
- (vector-push #\; *pasc-read-buffer*)
- (vector-push #\space *pasc-read-buffer*)
- (do ((ch (read-char stream) (read-char stream))
- saw-*)
- ((and saw-* (char= ch #\)))
- (list :comment (copy-seq *pasc-read-buffer*)))
- (cond ((char= ch #\*)
- (setq saw-* t))
- (t
- (setq saw-* nil)
- (vector-push ch *pasc-read-buffer*)
- (when (char= ch #\newline)
- (vector-push #\; *pasc-read-buffer*)
- (vector-push #\space *pasc-read-buffer*))))))
- (t
- (progn (unread-char next stream)
- char)))))
-
- (defun pasc-read-hex (stream char)
- (declare (ignore char))
- (let* ((number (let ((*read-base* 16)) (read stream)))
- (symbol (intern (format nil "#x~x" number))))
- (setf (symbol-value symbol) number)
- symbol))
-
- (defun pasc-read-binary (stream char)
- (declare (ignore char))
- (let* ((number (let ((*read-base* 2)) (read stream)))
- (symbol (intern (format nil "#b~b" number))))
- (setf (symbol-value symbol) number)
- symbol))
-
- (defun pasc-read-self (stream char)
- (declare (ignore stream))
- char)
-
- (defun pasc-read-self-symbol (stream char)
- (declare (ignore stream))
- (intern (make-string 1 :initial-element char)))
-
- (defun pasc-read-dot (stream char)
- (declare (ignore char))
- (let ((next (read-char stream)))
- (cond ((char= next #\.)
- :dots)
- (t
- (unread-char next stream)
- #\.))))
-
- (defun pasc-read-asterisk (stream char)
- (declare (ignore char))
- (if (eql #\* (peek-char nil stream))
- (progn
- (read-char stream)
- '**)
- '*))
-
- (setf (readtable-case *pasc-readtable*) :preserve)
- (set-syntax-from-char #\# #\a *pasc-readtable* *readtable*) ; get rid of # dispatch
- (set-syntax-from-char #\' #\" *pasc-readtable* *readtable*) ; ' = " !
-
- (set-macro-character #\{ 'pasc-read-comment nil *pasc-readtable*)
- (set-macro-character #\$ 'pasc-read-hex nil *pasc-readtable*)
- (set-macro-character #\% 'pasc-read-binary nil *pasc-readtable*)
- (set-macro-character #\; 'pasc-read-self nil *pasc-readtable*)
- (set-macro-character #\: 'pasc-read-self nil *pasc-readtable*)
- (set-macro-character #\= 'pasc-read-self nil *pasc-readtable*)
- (set-macro-character #\* 'pasc-read-asterisk nil *pasc-readtable*)
- (set-macro-character #\+ 'pasc-read-self-symbol nil *pasc-readtable*)
- (set-macro-character #\- 'pasc-read-self-symbol nil *pasc-readtable*)
- (set-macro-character #\^ 'pasc-read-self nil *pasc-readtable*)
- (set-macro-character #\( 'pasc-read-paren nil *pasc-readtable*)
- (set-macro-character #\) 'pasc-read-self nil *pasc-readtable*)
- (set-macro-character #\newline 'pasc-read-self nil *pasc-readtable*)
- (set-macro-character #\[ 'pasc-read-self nil *pasc-readtable*)
- (set-macro-character #\] 'pasc-read-self nil *pasc-readtable*)
- (set-macro-character #\] 'pasc-read-self nil *pasc-readtable*)
- (set-macro-character #\. 'pasc-read-dot nil *pasc-readtable*)
- (set-macro-character #\, 'pasc-read-self nil *pasc-readtable*)
-
- (defmacro fill-hash-table (table &rest command-function-list)
- (let ((table-sym (gensym))
- setf-code)
- (do ((list command-function-list (cddr list)))
- ((null list))
- (push `(setf (gethash ,(car list) ,table-sym) ,(cadr list))
- setf-code))
- `(let ((,table-sym ,table))
- ,@setf-code)))
-
- (defvar *pasc-types* (make-hash-table))
- (defvar *handle-tos* (make-hash-table))
- (defvar *spellings* (make-hash-table))
- (defvar *translated-files* nil)
- (defvar *not-in-rom* nil)
- (defvar *uncertain-traps* nil)
- (defvar *confused-traps* nil)
- (defvar *good-traps* 0)
- (defvar *bad-traps* 0)
- (defparameter *bad-traps-inline* t)
-
- ; Pascal compiler constants:
- (defvar true 1)
- (defvar false 0)
-
- ; The following "pre-defined" types are all the type defined in Types.p. We hard-code
- ; them in explicitely because we can't parse types.p. We make a types.lisp which
- ; we translate from the part of types.p which we can translate + some fixups
- ;
- (defun flush-pasc-types ()
- (clrhash *pasc-types*)
- (clrhash *handle-tos*)
- (clrhash *spellings*)
- (setq *good-traps* 0
- *bad-traps* 0)
- (fill-hash-table *pasc-types*
- 'char '(:character)
- 'boolean '(:boolean)
- 'signedbyte '(:signed-byte)
- 'byte '(:unsigned-byte)
- 'integer '(:signed-integer)
- 'oserr '(:signed-integer)
- 'scriptcode '(:signed-integer)
- 'langcode '(:signed-integer)
- 'longint '(:signed-long)
- 'integerptr '(:pointer)
- 'longintptr '(:pointer)
- 'Fixed '(:signed-long)
- 'fixedptr '(:pointer)
- 'Fract '(:signed-long)
- 'fractptr '(:pointer)
- 'ptr '(:pointer)
- 'procptr '(:pointer)
- 'handle '(:handle)
- 'str255 '((:string 255))
- 'Str63 '((:string 63))
- 'Str32 '((:string 32))
- 'Str31 '((:string 31))
- 'Str27 '((:string 27))
- 'Str15 '((:string 15))
- 'StringPtr '((:pointer (:string 255)))
- 'StringHandle '((:handle (:string 255)))
- 'ostype '(:ostype)
- 'ostypeptr '(:pointer)
- 'ResType '(:ostype)
- 'restypeptr '(:pointer)
- 'point '(:point)
- 'pointptr '(:pointer)
- 'extended '(:invalid-type)
- 'comp '(:invalid-type)
- 'file '(:invalid-type)
- 'object '(:invalid-type)
- 'rect '(:rect :record)
- )
- (setq *translated-files* (list "types")))
- (flush-pasc-types)
-
- (defvar *unrecognized-types* nil)
- (defvar *translate-pasc-dispatch* nil)
- (defvar *multiple-id-hack* nil)
- (defvar *record-packed-hack* nil)
- (defvar *exported-symbols* nil)
-
- (defvar *traps-package* :traps)
-
- (defun translate-pasc-file
- (&key (input-path (ccl::choose-file-dialog))
- (output-path
- (ccl::choose-new-file-dialog
- :directory (concatenate 'string (pathname-name input-path)
- ".lisp")
- :button-string "Translate"))
- dont-translate-includes
- dont-output-includes)
- (let ((temp-output-path (unless output-path
- (setq output-path
- (ccl::gen-file-name input-path)))))
- (unwind-protect
- (translate-pasc-file-internal
- input-path output-path dont-translate-includes dont-output-includes)
- (when temp-output-path
- (delete-file temp-output-path)))))
-
- (defun translate-pasc-file-internal (input-path output-path dont-translate-includes
- dont-output-includes)
- (with-open-file (istream input-path :direction :input)
- (with-open-file (ostream output-path :direction :output
- :if-exists :supersede)
- (let ((*readtable* *pasc-readtable*)
- (*package* (find-package :translate))
- (*print-case* :downcase)
- (input-directory (pathname-directory (ccl::stream-pathname istream)))
- (output-directory (pathname-directory (ccl::stream-pathname ostream)))
- (inhibit-newline nil)
- (*pasc-indent* 0)
- (*unrecognized-types* nil)
- (*multiple-id-hack* nil)
- (*record-packed-hack* nil)
- (*exported-symbols* nil))
- (format t "~%; Translating: ~s" (ccl::stream-pathname istream))
- (format ostream "~%(in-package :~a)" *traps-package*)
- (toplevel-mode nil nil nil)
- (reset-get-token)
- (do ((token (get-token istream :see-newline t :errorp nil)
- (get-token istream :see-newline t :errorp nil)))
- ((null token) t)
- (cond
- ((eq token #\newline)
- (if (zerop (ccl::stream-column ostream))
- (unless inhibit-newline
- (terpri ostream)
- (setq inhibit-newline t))
- (progn (terpri ostream)
- (setq inhibit-newline nil))))
- ((comment-p token)
- (when (find #\$ (cadr token))
- (let* ((comment-text (string-upcase (cadr token)))
- (index (search "$$SHELL" comment-text))
- dir-pos filename pathname name)
- (when index
- (setq dir-pos (position #\) comment-text :start index))
- (if dir-pos
- (setq index (1+ dir-pos))
- (incf index 7))
- (setq filename (subseq comment-text index))
- (setq pathname
- (probe-file
- (make-pathname :directory input-directory
- :name filename
- :defaults nil)))
- (format ostream "~%(require-interface '~a)"
- (subseq filename 0 (position #\. filename)))
- (if pathname
- (progn
- (setq name (pathname-name pathname))
- (unless (or dont-translate-includes
- (member name *translated-files* :test #'string-equal))
- (translate-pasc-file
- :input-path pathname
- :output-path
- (unless dont-output-includes
- (make-pathname :directory output-directory
- :name name
- :type "lisp"
- :defaults nil))
- :dont-output-includes dont-output-includes)
- (format t "~%; Continuing: ~s"
- (ccl::stream-pathname istream))))
- (unless dont-translate-includes
- (progn (break "~%; Warning: Can't find file ~s" filename)))))))
- (format-comment ostream token))
- (t
- (let ((func (gethash token (car *translate-pasc-dispatch*))))
- (if func
- (funcall func token istream ostream)
- (funcall (gethash :otherwise (car *translate-pasc-dispatch*))
- token istream ostream))))))
- (when *exported-symbols*
- (let ((*print-pretty* t))
- (format ostream "~%(export '~s)" *exported-symbols*)))
- (format ostream "~%(provide-interface '~a)"
- (pathname-name (ccl::stream-pathname ostream)))
- (when *unrecognized-types*
- (let ((rechecked nil))
- (dolist (type *unrecognized-types*)
- (unless (gethash type *pasc-types*)
- (push type rechecked)))
- (when rechecked
- (format t "~%; Error: Did not recognize these types or records: ~s"
- rechecked))))
-
- ) ; end of big let
- (push (pathname-name (ccl::stream-pathname istream)) *translated-files*))))
-
- (defvar *unget-token* nil)
- (defun get-token (istream &key (see-newline nil) (see-comma nil) (errorp t))
- (let ((token
- (if *unget-token*
- (prog1 *unget-token* (setq *unget-token* nil))
- (let ((new-token (read istream errorp nil)))
- (when (and new-token (symbolp new-token) (not (keywordp new-token)))
- (let* ((name (symbol-name new-token))
- (upcase-token (intern (string-upcase name))))
- (when (boundp new-token)
- (setf (symbol-value upcase-token)
- (symbol-value new-token)))
- (setf (gethash upcase-token *spellings*) name)
- (setq new-token upcase-token)))
- new-token))))
- (if (or (and (eq token #\newline) (not see-newline))
- (and (eq token #\,) (not see-comma)))
- (get-token istream :see-newline see-newline :see-comma see-comma :errorp errorp)
- token)))
-
- (defun unget-token (token)
- (setq *unget-token* token))
-
- (defun reset-get-token ()
- (setq *unget-token* nil))
-
- (defparameter *toplevel-dispatch* (make-hash-table))
- (fill-hash-table *toplevel-dispatch*
- 'CONST 'const-mode
- 'TYPE 'type-mode
- 'FUNCTION 'translate-function
- 'PROCEDURE 'translate-procedure
- :otherwise 'ignore)
-
- (defun toplevel-mode (token istream ostream)
- (declare (ignore token istream ostream))
- (setq *translate-pasc-dispatch* (list *toplevel-dispatch*)))
-
- (defun unget-toplevel-mode (token istream ostream)
- (declare (ignore istream ostream))
- (unget-token token)
- (setq *translate-pasc-dispatch* (list *toplevel-dispatch*)))
-
- (defun ignore (token istream ostream)
- (declare (ignore token istream ostream)))
-
- (defun parse-error (token istream ostream)
- (declare (ignore istream ostream))
- (error "Unexpected token ~s" token))
-
- (defun expecting (object istream &optional (test #'eq))
- (let ((token (get-token istream)))
- (unless (funcall test object token)
- (error "Was expecting ~s and got ~s instead" object token))))
-
- ;
- ; comments
- ;
-
- (defun comment-p (token)
- (and (consp token)
- (eq (car token) :comment)))
-
- (defun format-comment (ostream token)
- (if (plusp (ccl::stream-column ostream))
- (format ostream "~v,0t~a" *comment-column* (cadr token))
- (format ostream "~a" (cadr token))))
-
-
-
- ;
- ; functions & procedures!
- ;
-
- (defun translate-function (token istream ostream)
- (declare (ignore token))
- (let ((identifier (get-token istream))
- (args (parse-function-args istream))
- (returns (car (parse-type istream)))
- inline)
- (expecting #\; istream) ; eat the ; after the return type
- (setq inline (parse-inline-code istream))
- (generate-deftrap ostream identifier args returns inline)))
-
- (defun translate-procedure (token istream ostream)
- (declare (ignore token))
- (let ((identifier (get-token istream))
- (args (parse-procedure-args istream))
- inline)
- (setq inline (parse-inline-code istream))
- (generate-deftrap ostream identifier args nil inline)))
-
- (defun generate-deftrap (ostream identifier args returns inline &aux old-trap-mf trap-number)
- (cond
- (inline
- (let ((handled-inline)
- (length (length inline)))
- (if (= length 1)
- (generate-stack-deftrap ostream (car inline) identifier args returns inline)
- (progn
- (case (car inline)
- (#x3eb8 ; return the value of a global as a word
- (when (and (= length 2) (null args))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :no-trap `(%get-signed-word (%int-to-ptr ,(second inline)))
- identifier args
- (if returns `(:no-trap ,returns) nil)
- nil)))
- (#x2eb8 ; return the value of a global as a long
- (when (and (= length 2) (null args))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :no-trap `(%get-signed-long (%int-to-ptr ,(second inline)))
- identifier args
- (if returns `(:no-trap ,returns) nil)
- nil)))
- (#x303c ; put a constant word in d0
- (when (and (= length 3)
- (>= (third inline) #xa800))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :stack-trap (third inline) identifier args
- (if returns `(:stack ,returns) nil)
- (nconc `(:d0 ,(second inline))
- (mapcar #'(lambda (arg-pair) (car arg-pair)) args)))))
- (#x203c ; put a constant longword in d0
- (when (and (= length 4)
- (>= (fourth inline) #xa800))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :stack-trap (fourth inline) identifier args
- (if returns `(:stack ,returns) nil)
- (nconc `(:d0 (+ (ash ,(second inline) 16)
- ,(third inline)))
- (mapcar #'(lambda (arg-pair) (car arg-pair)) args)))))
- (#x3f3c ; push a constant word on the stack
- (when (and (= length 3)
- (>= (third inline) #xa800))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :stack-trap (third inline) identifier args
- (if returns `(:stack ,returns) nil)
- (nconc (mapcar #'(lambda (arg-pair) (car arg-pair)) args)
- `((,(second inline) :signed-integer))))))
- (#x2f3c ; push a constant longword on the stack
- (let (where)
- (when (or (and (= length 4)
- (>= (fourth inline) #xa800)
- (setq where :fourth))
- (and (= length 5)
- (>= (fifth inline) #xa800)
- (<= #x7000 (fourth inline) #x70ff)
- (setq where :fifth)))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :stack-trap (if (eq where :fourth)
- (fourth inline)
- (fifth inline))
- identifier args
- (if returns `(:stack ,returns) nil)
- (append (when (eq where :fifth)
- `(:d0 ,(ldb (byte 8 0) (fourth inline))))
- (mapcar #'(lambda (arg-pair) (car arg-pair)) args)
- `(((+ (ash ,(second inline) 16) ,(third inline))
- :signed-longint)))))))
- ((#x201f #x301f #x205f)
- (let ((reg (if (member (car inline) '(#x201f #x301f)) :d0 :a0)))
- (cond ((and (= length 2) ; really a register trap... 1 arg in reg, no return
- (= (length args) 1)
- (not returns))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :register-trap (second inline) identifier args
- nil
- `(,reg ,(caar args))))
- ((and (= length 3) ; really a register trap... 1 arg in reg, value in d0
- (= (length args) 1)
- (member (third inline) '(#x2e80 #x3e80)))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :register-trap (second inline) identifier args
- (if returns `(:d0 ,returns) nil)
- `(,reg ,(caar args))))
- ((and (= length 3) ; really a register trap... 2nd arg in d0, 1 arg in a0
- (= (length args) 2)
- (= (second inline) #x205f)
- (not returns))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :register-trap (third inline) identifier args
- nil
- `(,reg ,(caadr args) :a0 ,(caar args))))
- ((and (= length 4) ; really a register trap... 1 arg in reg, constant in d0
- ; return value in d0
- (= (length args) 1)
- (member (fourth inline) '(#x2e80 #x3e80))
- (<= #x7000 (second inline) #x70ff))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :register-trap (third inline) identifier args
- (if returns `(:d0 ,returns) nil)
- `(,reg ,(caar args) :d0 ,(ldb (byte 8 0) (second inline)))))
- ((and (= length 4) ; really a register trap... 2nd arg in d0, 1 arg in a0
- ; return value in d0
- (= (length args) 2)
- (member (fourth inline) '(#x2e80 #x3e80))
- (= (second inline) #x205f))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :register-trap (third inline) identifier args
- (if returns `(:d0 ,returns) nil)
- `(,reg ,(caadr args) :a0 ,(caar args)))))))
-
- (otherwise
- (cond
- ((and (<= #x7000 (car inline) #x70ff) ; MOVEQ word to d0
- (= length 2)
- (>= (second inline) #xa800))
- (setq handled-inline t)
- (format-deftrap
- ostream nil
- :stack-trap (second inline) identifier args
- (if returns `(:stack ,returns) nil)
- (nconc `(:d0 ,(ldb (byte 8 0) (car inline)))
- (mapcar #'(lambda (arg-pair) (car arg-pair)) args)))))))
- (unless handled-inline
- (format t "~%; ~a is not in ROM - INLINE = ~{ #x~16,4,'0,r~}"
- identifier inline)
- (format-deftrap ostream (format nil "Not in ROM - INLINE = ~{ #x~16,4,'0,r~}"
- inline)
- :stack-trap 0 identifier args
- (if returns `(:stack ,returns) nil)
- nil))))))
- ((setq trap-number (find-trap-number identifier)) ; do we have a trap number??
- (cond
- ((or (gethash identifier *register-trap-table*)
- (and (setq old-trap-mf
- (old-trap-macro-function identifier))
- (eq old-trap-mf (fboundp 'ccl::register-trap-macro-function))))
- (generate-register-deftrap ostream trap-number identifier args returns inline))
- ((or (>= trap-number #xa800)
- (and old-trap-mf
- (eq old-trap-mf (fboundp 'ccl::stack-trap-macro-function))))
- (generate-stack-deftrap ostream trap-number identifier args returns inline))
- (t
- (generate-register-deftrap ostream trap-number identifier args returns inline))))
- (t
- (format t "~%; ~a is not in ROM" identifier)
- (format-deftrap ostream "Not in ROM"
- :stack-trap 0 identifier args (if returns `(:stack ,returns) nil)
- nil))))
-
- (defun generate-stack-deftrap (ostream trap-number identifier args returns inline)
- (let ((bad-trap nil))
- (cond ((null inline)
- (when (eq (or (fboundp 'ccl::stack-trap-macro-function) t)
- (macro-function (intern (concatenate 'string "_"
- (symbol-name identifier))
- :ccl)))
- (format t "~%; Warning. Ignoring glue for trap ~s" identifier)
- (format ostream "~%; Warning. Ignoring glue for trap ~s" identifier)))
- ((= (length inline) 1)
- (unless (= (car inline) trap-number)
- (format t "~%; Warning. Trap number ~s (~a) doesn't match INLINE ~s"
- trap-number identifier (car inline))
- (format ostream "~%; Warning. Trap number ~s (~a) doesn't match INLINE ~s"
- trap-number identifier (car inline))))
- (t
- (format t "~%; Unrecognized INLINE code: ~s" inline)
- (setq bad-trap (format nil "Unrecognized INLINE code ~s" inline))))
- (format-deftrap ostream bad-trap :stack-trap trap-number identifier args
- (if returns `(:stack ,returns) nil)
- nil)))
-
- (defun generate-register-deftrap (ostream trap-number identifier args returns inline)
- (declare (ignore inline))
- (let ((rtrap (gethash identifier *register-trap-table*))
- bad-trap arg-registers return-register)
- (cond
- (rtrap
- (let ((table-args (copy-list (rtrap-entry rtrap)))
- (table-return (rtrap-exit rtrap))
- (missmatches nil))
- (dolist (arg args)
- (dolist (table-arg table-args
- (progn (push arg missmatches)
- (push :no-match arg-registers)))
- (when (args-match arg (cadr table-arg))
- (push (car table-arg) arg-registers)
- (setq table-args (delete table-arg table-args))
- (return))))
- (setq arg-registers (nreverse arg-registers))
- (cond ((null missmatches))
- ((= (length missmatches) 1 (length table-args))
- (let ((entry (car table-args)))
- (format t "~%; Warning. Assuming that ~s matches ~s in trap ~s"
- (cadr entry) (car missmatches) identifier)
- (format ostream "~%; Warning. Assuming that ~s matches ~s in trap ~s"
- (cadr entry) (car missmatches) identifier)
- (setq arg-registers
- (nsubst (car entry) :no-match arg-registers))))
- (t
- (format t "~%; Warning. Can't match 411 description of trap ~s!" identifier)
- (setq bad-trap
- (format nil "Can't match 411 description ~
- ~% Entry:~s ~% Exit:~s"
- (rtrap-entry rtrap) table-return))))
- (setq return-register (caar table-return))
- (unless (< (length table-return) 2)
- (unless (and (= (length table-return) 2)
- (eq (car (second table-return)) :d0)
- (find 'result (cadr (second table-return))))
- (format t "~%; Warning. Register trap ~s returns multiple values: ~s"
- identifier table-return)
- (format ostream "~%; Warning. Register trap ~s returns multiple values: ~s"
- identifier table-return)))))
- (t
- (format t "~%; No 411 description for register trap: ~s" identifier)
- (setq bad-trap "No 411 description")))
- (format-deftrap ostream bad-trap :register-trap trap-number identifier args
- (if returns `(,return-register ,returns) nil)
- (mapcan #'(lambda (arg register) (list register (car arg)))
- args arg-registers))))
-
- (defun format-deftrap (ostream bad-trap kind trap-number identifier args return
- trap-call-args)
- (setq args (remove :comment args
- :test #'(lambda (c a) (and (listp (car a)) (eq c (caar a))))))
- (setq trap-call-args (remove :comment trap-call-args
- :test #'(lambda (c a) (and (listp a) (eq c (car a))))))
- (let ((*readtable* *normal-readtable*))
- (cond
- (bad-trap
- (incf *bad-traps*)
- (unless *bad-traps-inline* (setq ostream t))
- (format ostream "~%#| ~a" bad-trap))
- (t
- (incf *good-traps*)))
- (format ostream "~%(deftrap _~a ~s~
- ~% ~s" identifier args return)
- (if (numberp trap-number)
- (format ostream "~% (~s #x~x~{ ~s~}))"
- kind trap-number trap-call-args)
- (format ostream "~% (~s ~s~{ ~s~}))"
- kind trap-number trap-call-args))
- (when bad-trap
- (format ostream "~%|#"))))
-
-
- (defun args-match (arg 411-desc)
- (or (ccl::memq (car arg) 411-desc)))
-
- (defun parse-function-args (istream &aux result var has-args)
- (loop
- (let ((token (get-token istream)))
- (case token
- (#\:
- (unless has-args
- (return))
- (let ((mactype (car (parse-type istream))))
- (dolist (id (nreverse *multiple-id-hack*))
- (push (list id (if var `(:pointer ,mactype) mactype)) result))
- (setq var nil
- *multiple-id-hack* nil)))
- (#\)
- (expecting #\: istream)
- (return))
- ((#\( #\; )) ; ignore left paren & semicolon
- (var (setq var t))
- (otherwise
- (setq has-args t)
- (push token *multiple-id-hack*)))))
- (nreverse result))
-
- (defun parse-procedure-args (istream &aux result var args)
- (loop
- (let ((token (get-token istream)))
- (case token
- (#\( (setq args t))
- (#\; (unless args (return)))
- (#\) (get-token istream) (return)) ; eat the ; after the ) first.
- (var (setq var t))
- (#\:
- (let ((mactype (car (parse-type istream))))
- (dolist (id (nreverse *multiple-id-hack*))
- (push (list id (if var `(:pointer ,mactype) mactype)) result))
- (setq var nil
- *multiple-id-hack* nil)))
- (otherwise
- (push token *multiple-id-hack*)))))
- (nreverse result))
-
- (defun parse-inline-code (istream &aux saw-inline result)
- (loop
- (let ((token (get-token istream)))
- (cond
- ((eq token 'inline) (setq saw-inline t))
- ((eq token #\;) (when saw-inline (return)))
- ((eq token '+)
- (unless (numberp (car result))
- (parse-error token istream t))
- (setq token (get-token istream))
- (unless (or (numberp token)
- (and (symbolp token)
- (boundp token)
- (numberp (setq token (symbol-value token)))))
- (parse-error token istream t))
- (incf (car result) token))
- ((symbolp token)
- (unless saw-inline
- (unget-token token)
- (return))
- (cond ((boundp token)
- (push (symbol-value token) result))
- (t
- (push (sharp-dollarify-identifier token) result))))
- ((numberp token) (push token result)))))
- (nreverse result))
-
- ; Constant declarations
- ;
-
- (defparameter *const-dispatch* (make-hash-table))
- (fill-hash-table *const-dispatch*
- 'CONST 'const-mode
- 'TYPE 'type-mode
- 'FUNCTION 'unget-toplevel-mode
- 'PROCEDURE 'unget-toplevel-mode
- 'VAR 'toplevel-mode
- 'END 'toplevel-mode
- 'END. 'toplevel-mode
- #\; 'parse-error
- #\: 'parse-error
- :otherwise 'translate-constant-decl)
-
- (defun const-mode (token istream ostream)
- (declare (ignore token istream ostream))
- (setq *translate-pasc-dispatch* (list *const-dispatch*)))
-
- (defun dollarify-identifier (id)
- (let* ((name (gethash id *spellings*))
- new-id
- (first-char (elt name 0)))
- (if (or (eq first-char #\_)
- (eq first-char #\#))
- id
- (progn
- (setq name (concatenate 'string "$" name))
- (setq new-id (intern (string-upcase name)))
- (setf (gethash new-id *spellings*) name)
- (when (boundp id)
- (setf (symbol-value new-id) (symbol-value id)))
- new-id))))
-
- (defun sharp-dollarify-identifier (id)
- (let* ((name (gethash id *spellings*))
- new-id
- (first-char (elt name 0)))
- (if (eq first-char #\#)
- id
- (progn
- (if (eq first-char #\_) ; make sure that bindings come from the $'d symbol
- (setq new-id (intern (string-upcase (concatenate 'string "#" name))))
- (setq new-id (intern (string-upcase (concatenate 'string "#$" name)))))
- (setf (gethash new-id *spellings*) name)
- (when (boundp id)
- (setf (symbol-value new-id) (symbol-value id)))
- new-id))))
-
- (defun translate-constant-decl (identifier istream ostream)
- (expecting #\= istream)
- (let ((value (fold-constants (parse-expression (get-expression-list istream)))))
- (format-constant identifier value ostream)))
-
-
- (defun format-constant (identifier value ostream)
- (ignore-errors
- (setf (symbol-value identifier) (eval value)))
- (setq identifier (dollarify-identifier identifier))
- (format ostream "(defconstant ~a " (gethash identifier *spellings*))
- (typecase value
- (string (if (= (length value) 4)
- (format ostream ":|~a|)" value) ; assume it's an ostype
- (format ostream "\"~a\")" value)))
- (otherwise (format ostream "~a)" value)))
- (push identifier *exported-symbols*))
-
-
- ; Type declarations
- ;
-
- (defparameter *type-dispatch* (make-hash-table))
- (fill-hash-table *type-dispatch*
- 'CONST 'const-mode
- 'TYPE 'type-mode
- 'FUNCTION 'unget-toplevel-mode
- 'VAR 'toplevel-mode
- 'PROCEDURE 'unget-toplevel-mode
- 'END 'toplevel-mode
- 'END. 'toplevel-mode
- #\; 'ignore
- #\: 'parse-error
- :otherwise 'translate-type-decl)
-
- (defparameter *record-dispatch* (make-hash-table))
- (fill-hash-table *record-dispatch*
- 'CONST 'parse-error
- 'TYPE 'parse-error
- 'FUNCTION 'parse-error
- 'PROCEDURE 'parse-error
- 'VAR 'parse-error
- #\; 'ignore
- #\: 'parse-error
- 'END 'end-record
- 'CASE 'translate-record-case
- :otherwise 'translate-record-field)
-
- (defun type-mode (token istream ostream)
- (declare (ignore token istream ostream))
- (setq *translate-pasc-dispatch* (list *type-dispatch*)))
-
- (defun translate-type-decl (identifier istream ostream)
- (expecting #\= istream)
- (let ((type (parse-type istream)))
- (cond
- ((eq type :record)
- (format ostream (if (gethash (ccl::make-keyword identifier) *handle-tos*)
- "(defrecord (~a :handle) "
- "(defrecord ~a ")
- (gethash identifier *spellings*))
- (push *record-dispatch* *translate-pasc-dispatch*)
- (incf *pasc-indent* 3)
- (setf (gethash identifier *pasc-types*)
- `(,(ccl::make-keyword identifier) :record)))
- ((and (consp type) (consp (car type)) (eq (caar type) :array)
- (dolist (idx (cddar type) t) (unless (integerp idx) (return nil))))
- (format ostream (if (gethash (ccl::make-keyword identifier) *handle-tos*)
- "(defrecord (~a :handle) "
- "(defrecord ~a ")
- (gethash identifier *spellings*))
- (format ostream "(array ~s))" `(array ,(cadar type) ,@(cddar type)))
- (setf (gethash identifier *pasc-types*)
- `(,(ccl::make-keyword identifier) :record)))
- (t
- (if (and (consp type)
- (eq (second type) :record))
- (format ostream "(%define-record :~a (find-record-descriptor ~s))"
- identifier (car type))
- (format ostream "(def-mactype :~a (find-mactype ~s))"
- identifier (if (consp (car type))
- (caar type)
- (car type))))
- (when (and (consp type) ; if it's a set, define the bits as constants
- (eq (cadr type) :set))
- (do ((bit 0 (1+ bit))
- (items (third type) (cdr items)))
- ((null items))
- (format ostream "~%")
- (format-constant (car items) bit ostream)))
- (setf (gethash identifier *pasc-types*)
- type)))))
-
- (defun translate-record-field (identifier istream ostream)
- (let ((next-token (get-token istream)))
- (cond
- ((eq next-token #\:)
- (let ((type (parse-type istream)))
- (case (car type)
- (:boolean
- (when *record-packed-hack*
- (format ostream "~%; ERROR!! Record field ~a declared PACKED BOOLEAN !~%" identifier)
- (format t "~%ERROR!! Record field declared PACKED BOOLEAN !")))
- (:unsigned-byte
- (unless *record-packed-hack*
- (format ostream "~%; ERROR!! Record field ~a declared Non-PACKED BYTE !~%" identifier)
- (format t "~%ERROR!! Record field declared Non-PACKED BYTE !")))
- (:character
- (unless *record-packed-hack*
- (format ostream "~%; ERROR!! Record field ~a declared Non-PACKED CHAR !~%" identifier)
- (format t "~%ERROR!! Record field declared Non-PACKED CHAR !"))))
-
- (cond
- (*multiple-id-hack*
- (dolist (id (nreverse (cons identifier *multiple-id-hack*)))
- (format ostream "~v,0t(~a ~s)~%" *pasc-indent*
- (gethash id *spellings*) (car type)))
- (setq *multiple-id-hack* nil))
- (t
- (format ostream "~v,0t(~a ~s)" *pasc-indent*
- (gethash identifier *spellings*) (car type))))))
- ((comment-p next-token)
- (format-comment ostream next-token)
- (terpri ostream))
- (t
- (push identifier *multiple-id-hack*)
- (translate-record-field next-token istream ostream)))))
-
- (defun end-record (token istream ostream)
- (declare (ignore token))
- (expecting #\; istream)
- (format ostream "~v,0t)" *pasc-indent*)
- (pop *translate-pasc-dispatch*)
- (decf *pasc-indent* 3)
- (setq *record-packed-hack* nil))
-
- (defparameter *record-case-dispatch* (make-hash-table))
- (fill-hash-table *record-case-dispatch*
- 'CONST 'parse-error
- 'TYPE 'parse-error
- 'FUNCTION 'parse-error
- 'PROCEDURE 'parse-error
- 'VAR 'parse-error
- 'CASE 'parse-error
- #\( 'translate-variants
- 'END 'end-record-case
- #\) 'end-record-case
- :otherwise 'ignore)
-
- (defun translate-record-case (token istream ostream)
- (declare (ignore token istream))
- (format ostream "~v,0t(:variant " *pasc-indent*)
- (push *record-case-dispatch* *translate-pasc-dispatch*)
- (incf *pasc-indent* 3))
-
- (defun end-record-case (token istream ostream)
- (declare (ignore istream))
- (format ostream "~v,0t)" *pasc-indent*)
- (pop *translate-pasc-dispatch*)
- (decf *pasc-indent* 3)
- (unget-token token))
-
- (defparameter *variant-dispatch* (make-hash-table))
- (fill-hash-table *variant-dispatch*
- 'CONST 'parse-error
- 'TYPE 'parse-error
- 'FUNCTION 'parse-error
- 'PROCEDURE 'parse-error
- 'VAR 'parse-error
- 'END 'parse-error
- #\; 'ignore
- #\: 'parse-error
- #\) 'end-variants
- 'CASE 'translate-record-case
- :otherwise 'translate-record-field)
-
- (defun translate-variants (token istream ostream)
- (declare (ignore token istream))
- (format ostream "~v,0t(" *pasc-indent*)
- (push *variant-dispatch* *translate-pasc-dispatch*))
-
- (defun end-variants (token istream ostream)
- (declare (ignore token istream))
- (format ostream "~v,0t)" *pasc-indent*)
- (pop *translate-pasc-dispatch*))
-
- (defun parse-type (istream &key (type-packed nil))
- (declare (notinline parse-type))
- (let ((token (get-token istream)))
- (case token
- (record
- (setq *record-packed-hack* type-packed)
- :record)
- (#\^
- (list
- (let ((next-thing (car (parse-type istream))))
- (if (and (consp next-thing)
- (eq (car next-thing)
- :pointer))
- (let ((handle-to (cadr next-thing)))
- (setf (gethash handle-to *handle-tos*) t)
- `(:handle ,handle-to))
- `(:pointer ,next-thing)))))
- (#\(
- (let* ((stuff (do ((token (get-token istream) (get-token istream))
- rresult)
- ((eq token #\)) (nreverse rresult))
- (push token rresult)))
- (length-o-stuff (length stuff)))
- `(,(cond ((< length-o-stuff 9)
- :unsigned-byte)
- ((< length-o-stuff 17)
- :unsigned-word)
- (t
- :unsigned-longint))
- :set ,stuff)))
- (set
- (expecting 'of istream)
- (parse-type istream))
- (packed
- (parse-type istream :type-packed t))
- (array
- (expecting #\[ istream)
- (let ((dimensions
- (do ((peek (get-token istream) (get-token istream))
- (dimensions))
- ((eq peek #\]) (nreverse dimensions))
- (unget-token peek)
- (let* ((size-type (parse-type istream))
- (size
- (ecase (cadr size-type)
- (:set (length (caddr size-type)))
-
- ; JBK don't evaluate the range, just build an expression to calculate it
- (:range `(- ,(cadddr size-type)
- ,(caddr size-type) -1)))))
-
- (push size dimensions)))))
- (expecting 'of istream)
- (let ((mac-type (car (parse-type istream))))
- (cond (type-packed
- (case mac-type
- (:boolean
- (let ((last-dim (last dimensions)))
- (setf (car last-dim) (ceiling (car last-dim) 8))
- (case (apply #'* dimensions)
- (1 '(:unsigned-byte))
- (2 '(:unsigned-integer))
- ((3 4) '(:unsigned-longint))
- (otherwise
- `((:array :byte ,@dimensions))))))
- (:character
- (if (and (= (length dimensions)1)
- (= (car dimensions) 4))
- '(:ostype)
- `((:array :character ,@dimensions))))
- (otherwise
- (unless (ccl:memq mac-type '(:byte :unsigned-byte :signed-byte))
- (format t "~%Warning! PACKED array of ~s found!"
- mac-type))
- `((:array ,mac-type ,@dimensions)))))
- (t
- `((:array ,mac-type ,@dimensions)))))))
- (string
- (let ((next (get-token istream)))
- (if (eq next #\[)
- (let ((size (get-token istream)))
- (expecting #\] istream)
- `((:string ,size)))
- `((:string 255)))))
- (univ
- (parse-type istream))
- (otherwise
- (let ((next (get-token istream :see-newline t)))
- (cond ((or (ccl:memq next '(#\; #\) #\newline #\])) ; must be a type name
- (comment-p next))
- (unget-token next)
- (or (gethash token *pasc-types*)
- (prog1 (list (ccl::make-keyword token))
- (unless (ccl:memq (ccl::make-keyword token) ccl:*record-types*)
- (pushnew token *unrecognized-types*)))))
- (t ; must be a dots thingy
- (unget-token next)
-
- ; JBK - remove the "evals" from the higher-range and lower-range
-
- (let ((lower-range (parse-expression
- (cons token (get-dots-expression-list istream)))))
-
- (expecting :dots istream)
- (let ((higher-range (parse-expression
- (get-dots-expression-list istream))))
-
-
- #|
-
- `(,(if (< (- higher-range lower-range) 256)
- :unsigned-byte
- :unsigned-integer)
- |#
- ; JBK just specify the larger of the two, -- I hope this doesn't introduce any bugs
- `(:unsigned-integer ; <- JBK instead of the above
- :range ,lower-range ,higher-range))))))))))
-
-
- ; Expression parsing
- ;
-
- (defmacro make-op (lisp-op precedence)
- `(cons ',lisp-op ,precedence))
-
- (defmacro lisp-op (op)
- `(car ,op))
-
- (defmacro precedence (op)
- `(cdr ,op))
-
-
- (defvar *operators* (make-hash-table))
-
- (fill-hash-table *operators*
- #\. (make-op bogus 10)
- '* (make-op * 3)
- '/ (make-op truncate 3)
- '+ (make-op + 2)
- '- (make-op - 2)
- '** (make-op expt 1))
-
- (defun get-operator (op-name)
- (or (gethash op-name *operators*)
- (error "Unrecognized operator ~s" op-name)))
-
- (defun unary-operator-p (op-name)
- (ccl::memq op-name '(- +)))
-
- (defun fold-constants (expr)
- (when (atom expr)
- (return-from fold-constants expr))
- (setf (cdr expr) (mapcar 'fold-constants (cdr expr)))
- (if (find-if-not #'numberp (cdr expr))
- expr
- (apply (car expr) (cdr expr))))
-
- (defun parse-expression (expr)
- (cond
- ((atom expr)
- (if (symbolp expr)
- (sharp-dollarify-identifier expr)
- expr))
- ((eq (car expr) :lisped)
- (cdr expr))
- (t
- (case (length expr)
- (1 ; single parenthetical expression
- (parse-expression (first expr)))
- (2 ; single unary operator expression
- (let ((op (get-operator (first expr))))
- (list (lisp-op op) (parse-expression (second expr)))))
- (3 ; single binary operator expression
- (if (eq (second expr) #\.)
- (let ((*readtable* *normal-readtable*))
- (read-from-string (format nil "~d.~d" (first expr) (third expr))))
- (let ((op (get-operator (second expr))))
- (list (lisp-op op)
- (parse-expression (first expr))
- (parse-expression (third expr))))))
- (otherwise ; some sort of extended expression
- (cond ((unary-operator-p (first expr)) ; i.e. - 3 * 7 ...
- (let ((rest (cddr expr)))
- (setf (cddr expr) nil)
- (parse-expression (cons expr rest))))
- ((unary-operator-p (third expr)) ; i.e. 3 * - 7 ...
- (let* ((unary-expr (cddr expr))
- (rest (cddr unary-expr)))
- (setf (cddr unary-expr) nil)
- (setf (cddr expr) (list unary-expr))
- (parse-expression (append expr rest))))
-
- (t ; extended expression
- (let ((op1 (get-operator (second expr)))
- (op2 (get-operator (fourth expr))))
- (cond ((> (precedence op1) (precedence op2))
- (let ((rest (cdddr expr)))
- (setf (cdddr expr) nil)
- (parse-expression (cons expr rest))))
- (t
- (list (lisp-op op1)
- (parse-expression (first expr))
- (parse-expression (cddr expr)))))))))))))
-
- (defun get-expression-list (istream)
- (let ((expr-list nil))
- (do ((token (get-token istream) (get-token istream)))
- ((or (eq token #\;) (eq token #\))) (nreverse expr-list))
- (case token
- (sizeof
- (expecting #\( istream) ; eat the (
- (push `(:lisped record-length ,(ccl::make-keyword (get-token istream)))
- expr-list)
- (expecting #\) istream)) ; eat the )
- (#\(
- (push (get-expression-list istream) expr-list))
- (otherwise
- (push token expr-list))))))
-
- (defun get-dots-expression-list (istream)
- (let ((expr-list nil))
- (do ((token (get-token istream :see-newline t :see-comma t)
- (get-token istream :see-newline t :see-comma t)))
- ((ccl:memq token '(#\) #\newline :dots #\] #\, #\;)) (when (ccl:memq token '(:dots #\]))
- (unget-token token))
- (nreverse expr-list))
- (if (eq token #\()
- (push (get-expression-list istream) expr-list))
- (push token expr-list))))
-
- #|
- (defun test (string)
- (let ((*readtable* *pasc-readtable*))
- (parse-expression
- (get-expression-list (make-string-input-stream string)))))
-
- (defun test2 (string)
- (let ((*readtable* *pasc-readtable*))
- (get-expression-list (make-string-input-stream string))))
- |#
-
- (ccl:provide :pasc-reader)
-